package com.mallcai.bigdata.ladon.datasource;

import com.cake.bigdata.starter.exception.category.BusinessException;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.mallcai.bigdata.ladon.datasource.task.ExportDataRunnable;
import com.mallcai.bigdata.ladon.dpl.entity.common.Datasource;
import com.mallcai.bigdata.ladon.service.system.IMailService;
import com.mallcai.bigdata.ladon.vo.DataVo;
import com.mallcai.bigdata.ladon.vo.ExportParam;
import com.mallcai.bigdata.ladon.vo.QueryParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.concurrent.*;

/**
 * Created by oneape<oneape15@163.com>
 * Created 2019-06-04 09:43.
 * Modify:
 */
public abstract class AbstractDataSource {

    private ExecutorService executor = new ThreadPoolExecutor(40, 200,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(1024), new ThreadFactoryBuilder()
            .setNameFormat("demo-pool-%d").build(), new ThreadPoolExecutor.AbortPolicy());

    protected static final long NS_MS = 1000 * 1000; //将ns(纳秒)转换成ms(毫秒)

    protected static final String KEY_LIMIT    = " LIMIT ";
    public static final    int    ONE_MAX_SIZE = 1000; //一次查询最多条数

    protected DataSource dataSource;
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    private volatile boolean isClose = true;

    public AbstractDataSource(Datasource ds) {
        this.dataSource = getDataSource(ds);
        this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(this.dataSource);
    }

    public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
        return namedParameterJdbcTemplate;
    }

    public abstract DataSource initDataSource(Datasource ds);

    public DataSource getInnerDataSource(){
        return this.dataSource;
    }

    /**
     * 获取数据源
     *
     * @param ds Datasource
     * @return DataSource
     */
    public DataSource getDataSource(Datasource ds) {
        synchronized (this) {
            if (this.dataSource == null) {
                this.dataSource = initDataSource(ds);
            }
        }
        return this.dataSource;
    }

    /**
     * 获取连接对象.
     *
     * @return Connection
     */
    public abstract Connection getConnection() throws BusinessException;

    /**
     * 是否支持分页
     *
     * @return boolean
     */
    public abstract boolean supportPage();

    /**
     * 判断数据源是不关闭
     *
     * @return boolean
     */
    public boolean isClose() {
        return this.isClose;
    }


    /**
     * 执行查询语句
     *
     * @param queryParam QueryParam
     * @return DataVo
     */
    public abstract DataVo execSql(QueryParam queryParam) throws BusinessException;

    /**
     * 判断是否以Limit结束, 过滤子查询的limit
     *
     * @param sql String
     * @return boolean
     */
    protected boolean isEndWithLimit(String sql) {
        int lastIndex = StringUtils.lastIndexOf(StringUtils.upperCase(sql), KEY_LIMIT);
        if (lastIndex > 0) {
            String afterLimitStr = StringUtils.substring(sql, lastIndex + KEY_LIMIT.length()); //获取最后一个limit后的字符中
            afterLimitStr = StringUtils.trimToEmpty(afterLimitStr);
            for (int i = 0; i < afterLimitStr.length(); i++) {
                char ch = afterLimitStr.charAt(i);
                if (ch != ',' && ch != '?' && ch != ' ' && (ch < '0' || ch > '9')) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    /**
     * 修改limit操作是否超过了最大值
     *
     * @param sql String
     * @return String
     */
    protected String editLimitIfOverMax(String sql) {
        int lastIndex = StringUtils.lastIndexOf(StringUtils.upperCase(sql), KEY_LIMIT);
        if (lastIndex <= 0) {
            return sql;
        }

        String nSql = StringUtils.substring(sql, 0, lastIndex);
        String afterLimitStr = StringUtils.substring(sql, lastIndex + KEY_LIMIT.length());
        afterLimitStr = StringUtils.trimToEmpty(afterLimitStr);
        if (StringUtils.isBlank(afterLimitStr)) {
            throw new BusinessException(String.format("limit关键字后必须带有效数字!, sql: {}", sql));
        }
        String[] nums = StringUtils.split(afterLimitStr, ",");

        String limitStr;
        String tmp;
        // limit 200 模式
        if (nums.length == 1) {
            try {
                tmp = StringUtils.trimToEmpty(nums[0]);
                if (StringUtils.equals(tmp, "?")) { // sql占位符
                    limitStr = " " + tmp;
                } else {
                    int size = Integer.parseInt(tmp);
                    if (size < ONE_MAX_SIZE) {
                        limitStr = " " + size;
                    } else {
                        limitStr = " " + ONE_MAX_SIZE;
                    }
                }
            } catch (Exception e) {
                throw new BusinessException("Limit数据类型有误, SQL: " + sql);
            }
        } else if (nums.length == 2) {
            // limit 0 , 200 模式
            int startSize, endSize;
            tmp = StringUtils.trimToEmpty(nums[0]);
            String tmp2 = StringUtils.trimToEmpty(nums[1]);
            if (StringUtils.equals(tmp, "?") || StringUtils.equals(tmp2, "?")) { // sql占位符
                if (StringUtils.equals(tmp, "?")) {
                    limitStr = " " + tmp;
                } else {
                    try {
                        startSize = Integer.parseInt(tmp);
                        if (startSize > ONE_MAX_SIZE) {
                            startSize = ONE_MAX_SIZE;
                        }
                    } catch (Exception e) {
                        throw new BusinessException("Limit数据类型有误, SQL: " + sql);
                    }
                    limitStr = " " + startSize;
                }

                if (StringUtils.equals(tmp2, "?")) {
                    limitStr = limitStr + "," + tmp2;
                } else {
                    try {
                        endSize = Integer.parseInt(tmp2);
                        if (endSize > ONE_MAX_SIZE) {
                            endSize = ONE_MAX_SIZE;
                        }
                    } catch (Exception e) {
                        throw new BusinessException("Limit数据类型有误, SQL: " + sql);
                    }
                    limitStr = limitStr + "," + endSize;
                }
            } else {
                try {
                    startSize = Integer.parseInt(tmp);
                    endSize = Integer.parseInt(tmp2);
                } catch (Exception e) {
                    throw new BusinessException("Limit数据类型有误, SQL: " + sql);
                }

                if (endSize <= startSize) {
                    throw new BusinessException("无效的limit范围, SQL: " + sql);
                }

                if (endSize > ONE_MAX_SIZE) {
                    endSize = ONE_MAX_SIZE;
                }

                limitStr = " " + startSize + "," + endSize;
            }
        } else {
            throw new BusinessException("limit格式有误!!, SQL: " + sql);
        }

        return nSql + " " + KEY_LIMIT + limitStr;
    }

    /**
     * 发送数据到邮箱
     *
     * @param params ExportParam
     * @return int
     */
    public int exportData2Email(ExportParam params, IMailService iMailService) {
        executor.execute(new ExportDataRunnable(getConnection(), params, iMailService));
        return 1;
    }

}
